package beaver.game;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Queue;

import org.newdawn.fizzy.World;


public class RemoteConnection implements Runnable{
	
	private Socket localToRemote = null;
	private Socket remoteToLocal = null;
	private ServerSocket localHost = null;
	private Queue<String> received = null;
	private Thread t = null;
	private DataInputStream inbound = null;
	private DataOutputStream outbound = null;
	private boolean kill = false;
	private boolean isHost;
	private String remoteConn;
	
	
	public static final int HOST_SERVER_PORT = 44444;
	public static final int OTHER_SERVER_PORT = 33333;
	
	public RemoteConnection(String remoteConn, boolean isHost) {
		received = new LinkedList<String>();
		this.remoteConn = remoteConn;
		this.isHost = isHost;
		connect();
		
	}
	
	public void reConnect(){
		kill = true;
		while(kill){
			System.out.println("Waiting for server to terminate");
		}
		try {
			outbound.writeUTF("reset");
		} catch (IOException e) {
			e.printStackTrace();
			System.err.println("Error sending reset");
		}
		connect();
		
	}
	
	public void connect(){
		//Handshaking connection
				try {
					
					if(isHost){
						localHost = new ServerSocket(HOST_SERVER_PORT);
						System.out.println("(HOST) Waiting for inbound connection");
						remoteToLocal = localHost.accept();
						System.out.println("(HOST) Inbound established, attempting outbound");
						localToRemote = new Socket(remoteConn,OTHER_SERVER_PORT);
						System.out.println("(HOST) Outbound established");
						
					}
					else{
						System.out.println("Attempting to establish outbound connection");
						localToRemote = new Socket(remoteConn,HOST_SERVER_PORT);
						localHost = new ServerSocket(OTHER_SERVER_PORT);
						System.out.println("Outbound established, waiting for inbound connection");
						remoteToLocal = localHost.accept();
						System.out.println("Inbound established");
					}
					
					outbound = new DataOutputStream(localToRemote.getOutputStream());
					inbound = new DataInputStream(remoteToLocal.getInputStream());
					String message;
					if(isHost){
						message = inbound.readUTF();
						System.out.println("(HOST) Received: " + message);
						if(message.equalsIgnoreCase("sendack")){
							outbound.writeUTF("ackreceived");
							System.out.print("(HOST) Sent: " + message);
						}
						
					}
					else{
						outbound.writeUTF("sendack");
						System.out.println("Sent: " + "sendack");
						message = inbound.readUTF();
						System.out.println("Received: " + message);
						
					}
					
				} catch (IOException e) {
					e.printStackTrace();
					System.err.println("Error establishing connection");
				}
				
				run();
	}
	
	public void run(){
		
		t = new Thread(){
			public void run(){
			
				try {
					while(true&&!kill){
						String message = inbound.readUTF();
						received.add(message);
						if(message.equalsIgnoreCase("exit")){
							inbound.close();
							remoteToLocal.close();
							localHost.close();
							break;
						}
						if(message.equalsIgnoreCase("reset")){
							System.out.println("Reset signal received");
						}
					}
					kill = false;
				} catch (IOException e) {
					e.printStackTrace();
				}
				
			}
		};
		
		t.start();
		
		
	}
	
	public String getMove(){
		String move = null;
		if(hasMoves()){
			move = received.remove();
		}
		return move;
	}
		
	public GameplayState receiveAll(){
		return null;
	}
	
	public void sendAll(GameplayState game){
		
	}
	
	
	
	public void sendMove(String move) throws IOException{
		DataOutputStream outbound = new DataOutputStream(localToRemote.getOutputStream());
		outbound.writeUTF(move);
	}
	
	public boolean hasMoves(){
		return (received.peek()!=null);
	}
	public void close() throws IOException{
		
		outbound.writeUTF("exit");
		outbound.close();
		localToRemote.close();
	
		
	}
	
	
}
